﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Web;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using ScrumTable.Common;
using ScrumTable.Common.Collections;

#endregion

namespace ScrumTable.DL.Data.TFS.Services.TeamFoundation
{
    /// <summary>
    /// Represents the attachment wrapper which is used to handle the
    /// associated file on the file system.
    /// </summary>
    public class TfsAttachment : DisposeBase
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        /// <summary>
        /// Gets the start character for the old uri entry in the attachment
        /// comment. This is necessary if an attachment should be replaced.
        /// </summary>
        internal const char CommentIdStart = '[';

        /// <summary>
        /// Gets the end character for the old uri entry in the attachment
        /// comment. This is necessary if an attachment should be replaced.
        /// </summary>
        internal const char CommentIdEnd = ']';

        /// <summary>
        /// Contains additional data which is associated to the current instance
        /// and should be deleted when the current instance will be deleted.
        /// </summary>
        public IDictionary<string, IDisposable> PropertyData { get; private set; }

        /// <summary>
        /// Gets the default attachment id.
        /// </summary>
        public const int DefaultId = -1;

        private readonly int _id;
        private readonly Attachment _data;

        private string _filePath;

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        /// <summary>
        /// Gets the id of the underlying attachment.
        /// </summary>
        public int Id
        {
            get { return _id; }
        }

        /// <summary>
        /// Gets the underlying data native tfs implementation.
        /// </summary>
        public Attachment Data { get { return _data; } }

        /// <summary>
        /// Gets the local path of the current element.
        /// </summary>
        public string LocalPath
        {
            get
            {
                if (_data != null && _filePath == null)
                {
                    string comment = _data.Comment ?? string.Empty;
                    string oldUriLine = comment;
                    int oldUriLineEnd = oldUriLine.IndexOf(Environment.NewLine);

                    if (oldUriLineEnd != -1)
                    {
                        oldUriLine = comment.Substring(0, oldUriLineEnd);
                    }

                    int uriStart = oldUriLine.IndexOf(CommentIdStart);

                    if (uriStart != -1 && oldUriLine.EndsWith(CommentIdEnd.ToString()))
                    {
                        _filePath = oldUriLine.Substring(uriStart + 1, oldUriLine.Length - uriStart - 2);
                    }
                }
                return _filePath;
            }
        }

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        internal TfsAttachment(Attachment data, string filePath = null)
        {
            PreCondition.AssertNotNull(data, "data");

            PropertyData = new Dictionary<string, IDisposable>(0);

            _data = data;
            _id = TryGetIdFromAttachmentUri(data);
            _filePath = filePath;
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Tries to extract the attachment file id from the given Uri.
        /// </summary>
        /// <param name="toGetId">Specifies the Uri to extract the id.</param>
        /// <returns>Returns the extracted uri or a null reference if it could not be found.</returns>
        public static int TryGetIdFromAttachmentUri(Attachment toGetId)
        {
            if (toGetId == null || toGetId.Uri == null)
                return DefaultId;

            return TryGetIdFromAttachmentUri(toGetId.Uri);
        }

        /// <summary>
        /// Releases managed (c# or .net) resources.
        /// </summary>
        protected override void ReleaseManagedResources()
        {
            PropertyData.ForEach(
                pair =>
                    {
                        if (pair.Value != null)
                        {
                            pair.Value.Dispose();
                        }
                    });

            if (_filePath != null)
            {
                DirectoryInfo directory = new DirectoryInfo(_filePath);

                if (directory.Exists)
                {
                    directory.Delete(true);
                }
            }
        }

        private static int TryGetIdFromAttachmentUri(Uri attaUri)
        {
            if (string.IsNullOrEmpty(attaUri.Query))
                return DefaultId;

            string fileId = HttpUtility.ParseQueryString(attaUri.Query)["FileID"];

            if (!string.IsNullOrEmpty(fileId))
            {
                int parsedValue;
                if (int.TryParse(fileId, NumberStyles.Integer, CultureInfo.InvariantCulture, out parsedValue))
                {
                    return parsedValue;
                }
            }
            return DefaultId;
        }

        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        #endregion
    }
}